#include <stdio.h>
#include "mtlib.c"
#include <stdarg.h>
#include <sys/time.h>
#include <signal.h>

int mostrarMensaje (const char *, ...);
void procesarMensaje (unsigned char, mti_mensaje);
int calcularSuma (char *, unsigned int);
void terminar (int);

volatile sig_atomic_t continuar = 1;
unsigned long long horaReferencia;

int main(void) {
  unsigned char centro;
  unsigned int conUnix, conIPv4;
  mti_mensaje sigMensaje;
  struct timeval hora;
  signal(SIGINT, &terminar);
  gettimeofday(&hora, NULL);
  horaReferencia = hora.tv_sec * 1000000 + hora.tv_usec;
  centro = mtf_obtener_descriptor(1024);
  mostrarMensaje("Centro de mensajes: %hu", centro);
  conUnix = mtf_conectar(centro, MTP_UNIX_ESCUCHA, "/root/socket42.tmp");
  mostrarMensaje("Conexión UNIX en /root/socket42.tmp: número %lu", conUnix);
  conIPv4 = mtf_conectar(centro, MTP_IPV4_ESCUCHA, MTH_CUALQUIER_IP, 4456);
  mostrarMensaje("Conexión IPv4 en cualquier IP, puerto 4456: número %lu", conIPv4);
  while(continuar) {
    if (!mtf_recibir_mensajes(centro)) continue;
    sigMensaje = mtf_siguiente_mensaje(centro);
    procesarMensaje(centro, sigMensaje);
    mtf_descartar_mensaje(centro, sigMensaje.codigo);
  }
  mtf_desconectar(centro, conUnix);
  mtf_desconectar(centro, conIPv4);
  mtf_liberar_descriptor(centro);
  mostrarMensaje("Cerrando aplicación");
  return 0;
}

int mostrarMensaje (const char * mensaje, ...) {
  va_list parametros;
  struct timeval hora;
  unsigned long long diferencia;
  unsigned long long segundos, microsegundos;
  int resultado = 0;
  va_start(parametros, mensaje);
  gettimeofday(&hora, NULL);
  diferencia = (hora.tv_sec * 1000000 + hora.tv_usec) - horaReferencia;
  segundos = diferencia / 1000000;
  microsegundos = diferencia % 1000000;
  resultado += printf("[% 5llu.%06llu]", segundos, microsegundos);
  resultado += vprintf(mensaje, parametros);
  resultado += printf("\n");
  return resultado;
}

void procesarMensaje (unsigned char centro, mti_mensaje mensaje) {
  char datos[517];
  unsigned int descriptor;
  int suma;
  switch(mensaje.categoria) {
  case MTA_ACEPTAR:
    if (mensaje.tipo) {
      mtf_obtener_datos(centro, mensaje.codigo, (unsigned long int *) &descriptor);
      mostrarMensaje("Conexión entrante: número %lu, originada de conexión %lu", mensaje.remitente, descriptor);
    } else
      mostrarMensaje("Conexión entrante: número %lu, proveniente de centro %hu", mensaje.remitente, mtf_conexion_es_interna(centro, mensaje.remitente));
    break;
  case MTA_CERRAR:
    mostrarMensaje("Conexión cerrada: número %lu", mensaje.remitente);
    break;
  case MTA_HANDSHAKE:
    mtf_obtener_datos(centro, mensaje.codigo, (void **) &datos);
    suma = calcularSuma(datos, mensaje.tipo);
    mostrarMensaje("Handshake recibido: conexión %lu, tamaño %hu, suma de datos %d", mensaje.remitente, mensaje.tipo, suma);
    break;
  default:
    mostrarMensaje("Mensaje recibido: conexión %lu, tipo de mensaje %hu", mensaje.remitente, mensaje.tipo);
  }
}

int calcularSuma (char * datos, unsigned int cantidadDatos) {
  int suma;
  for (suma = 0; cantidadDatos; datos ++) suma += *datos;
  return suma;
}

void terminar (int sigrcv) {
  continuar = 0;
}